package com.snow.auth.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.snow.auth.component.AuthComponent;
import com.snow.auth.controller.SystemAuthController;
import com.snow.auth.entity.*;
import com.snow.auth.model.LoginUser;
import com.snow.auth.model.SystemUserInfo;
import com.snow.auth.model.TenantInfo;
import com.snow.auth.model.WechatLoginUser;
import com.snow.auth.repository.*;
import com.snow.exception.CommonRuntimeException;
import com.snow.jpa.BaseService;
import com.snow.model.ILoginUser;
import com.snow.starter.SnowAutoConfiguration;
import com.snow.view.WebResponse;
import com.snow.wechat.component.WeChatComponent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * auth业务
 *
 * @author by 13119
 */
@Slf4j
@Service
public class SystemAuthService extends BaseService<SystemUserRepository, SystemUser, Integer> {
    final AuthComponent authComponent;
    final SystemUserRoleRepository systemUserRoleRepository;
    final SystemRoleRepository systemRoleRepository;
    final SnowAutoConfiguration snowAutoConfiguration;
    final SystemTenantRepository systemTenantRepository;
    final WechatUserRepository wechatUserRepository;
    final WeChatComponent weChatComponent;

    public SystemAuthService(SystemUserRepository repository, AuthComponent authComponent
            , SystemUserRoleRepository systemUserRoleRepository, SystemRoleRepository systemRoleRepository, SnowAutoConfiguration snowAutoConfiguration, SystemTenantRepository systemTenantRepository, WechatUserRepository wechatUserRepository, WeChatComponent weChatComponent) {
        super(repository);
        this.authComponent = authComponent;
        this.systemUserRoleRepository = systemUserRoleRepository;
        this.systemRoleRepository = systemRoleRepository;
        this.snowAutoConfiguration = snowAutoConfiguration;
        this.systemTenantRepository = systemTenantRepository;
        this.wechatUserRepository = wechatUserRepository;
        this.weChatComponent = weChatComponent;

    }


    @Transactional(rollbackFor = Exception.class)
    public WebResponse<Object> login(SystemAuthController.LoginParams params) {
        SystemUser queryUser = new SystemUser();
        queryUser.setAccount(params.getAccount());
        Optional<SystemUser> systemUser = repository.findOne(Example.of(queryUser));
        if (!systemUser.isPresent()) {
            return WebResponse.fail("用户信息无效");
        }
        SystemUser currentUser = systemUser.get();
        if (!params.getPassword().equals(currentUser.getPassword())) {
            throw new CommonRuntimeException("账号或密码错误");
        }
        SystemTenant tenant = systemTenantRepository.findById(currentUser.getTenantId()).orElseThrow(() -> new CommonRuntimeException("租户信息无效"));
        if (snowAutoConfiguration.getEnableTenantExpired() && !currentUser.getSystemAdmin()) {
            if (tenant.getExpiredDate().before(new Date())) {
                if (tenant.getPhone().equals(currentUser.getPhone())) {
                    return WebResponse.fail(1, "该租户已过期", JSONUtil.parseObj(tenant));
                }
                return WebResponse.fail("系统使用期限已过期，请联系管理员续费");
            }
        }
        LoginUser loginUser = BeanUtil.copyProperties(currentUser, LoginUser.class);
        List<SystemUserRole> userRoles = systemUserRoleRepository.lambdaQuery().disTenantFilter().equal("userId", loginUser.getId()).findAll();
        List<SystemRole> roles = systemRoleRepository.lambdaQuery().disTenantFilter().in("id", userRoles.stream().map(SystemUserRole::getRoleId).toArray()).findAll();
        for (SystemRole role : roles) {
            loginUser.getPermissions().addAll(JSONUtil.toList(role.getPermissions(), String.class));
        }
        String token = authComponent.generateToken(loginUser);
        loginUser.setToken(token);
        // 缓存系统用户到Redis中，返回前台基本用户信息
        return WebResponse.success(token);
    }

    @Transactional(rollbackFor = Exception.class)
    public LoginUser loginByOpenId(String openId) {
        SystemUser currentUser = repository.findBy("openId", openId);
        if (currentUser == null) {
            throw new CommonRuntimeException("用户信息无效");
        }
        SystemTenant tenant = systemTenantRepository.findById(currentUser.getTenantId()).orElseThrow(() -> new CommonRuntimeException("租户信息无效"));
        if (snowAutoConfiguration.getEnableTenantExpired() && !currentUser.getSystemAdmin()) {
            if (tenant.getExpiredDate().before(new Date())) {
                throw new CommonRuntimeException("用户信息无效");
            }
        }
        LoginUser loginUser = BeanUtil.copyProperties(currentUser, LoginUser.class);
        List<SystemUserRole> userRoles = systemUserRoleRepository.lambdaQuery().disTenantFilter().equal("userId", loginUser.getId()).findAll();
        List<SystemRole> roles = systemRoleRepository.lambdaQuery().disTenantFilter().in("id", userRoles.stream().map(SystemUserRole::getRoleId).toArray()).findAll();
        for (SystemRole role : roles) {
            loginUser.getPermissions().addAll(JSONUtil.toList(role.getPermissions(), String.class));
        }
        String token = authComponent.generateToken(loginUser);
        loginUser.setToken(token);
        // 缓存系统用户到Redis中，返回前台基本用户信息
        return loginUser;
    }

    public WebResponse<Void> logout() {
        authComponent.cancelToken();
        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    public void changePwd(String oldPwd, String newPwd) {
        ILoginUser currentUser = authComponent.getCurrentUser();
        SystemUser user = repository.getById(currentUser.getId());
        if (!user.getPassword().equals(oldPwd)) {
            throw new CommonRuntimeException("密码错误，修改失败");
        }
        user.setPassword(newPwd);
        save(user);
    }

    public WechatLoginUser wechatLogin(SystemAuthController.OpenIdLoginParams params) {
        WechatUserEntity wechatUser = wechatUserRepository.lambdaQuery().equal("openId", params.getOpenId()).disTenantFilter().one();
        if (wechatUser == null) {
            if (StrUtil.isBlank(params.getPhoneCode())) {
                throw new CommonRuntimeException("找不到登录用户信息，请注册");
            }
            JSONObject phoneInfo = weChatComponent.getPhoneNumber(params.getPhoneCode());
            wechatUser = new WechatUserEntity();
            wechatUser.setName("微信用户_" + RandomUtil.randomString(6));
            wechatUser.setPhone(phoneInfo.getStr("purePhoneNumber"));
            wechatUser.setOpenId(params.getOpenId());
            wechatUser.setCreateTime(new Date());
            wechatUserRepository.save(wechatUser);
        }
        WechatLoginUser wechatLoginUser = new WechatLoginUser();
        wechatLoginUser.setId(wechatUser.getId());
        wechatLoginUser.setName(wechatUser.getName());
        wechatLoginUser.setAccount(wechatUser.getOpenId());
        wechatLoginUser.setPhone(wechatUser.getPhone());
        SystemUser systemUser = repository.lambdaQuery().disTenantFilter().findBy("openId", wechatLoginUser.getAccount());
        wechatLoginUser.setManager(systemUser != null);
        wechatLoginUser.setManagerInfo(BeanUtil.copyProperties(systemUser, SystemUserInfo.class));
        if (systemUser != null) {
            wechatLoginUser.setTenantInfo(BeanUtil.copyProperties(systemTenantRepository.findById(systemUser.getTenantId()).get(), TenantInfo.class));
            wechatLoginUser.setUserId(systemUser.getId());
        }
        if (wechatLoginUser.getManager()) {
            List<SystemUserRole> userRoles = systemUserRoleRepository.lambdaQuery().disTenantFilter().equal("userId", systemUser.getId()).findAll();
            List<SystemRole> roles = systemRoleRepository.lambdaQuery().disTenantFilter().in("id", userRoles.stream().map(SystemUserRole::getRoleId).toArray()).findAll();
            for (SystemRole role : roles) {
                wechatLoginUser.getPermissions().addAll(JSONUtil.toList(role.getPermissions(), String.class));
            }
        }
        String token = authComponent.generateToken(wechatLoginUser);
        wechatLoginUser.setToken(token);
        return wechatLoginUser;
    }
}
